package testjeu;

import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.tiled.TiledMap;
                    
                   
/**
 * Charge une map créée via l'utilitaire TiledMap et en extrait les caractéristiques
 * @author YoTsumi
 */
public class map extends Jeu  implements Constantes {

 
    
    // Infos sur la map loadé
    private String nom;
    private String auteur;
    private String suivant;
    
    private String nomFichier;
    
    private Actions[][] actionsMap = new Actions[16][16]; // 16 car on veut commencer à l'indice 1
    private Actions[][] actionsOriginalesMap = new Actions[16][16]; 
    private ArrayList<TankEnnemi>   listeEnnemis = new ArrayList<TankEnnemi>(); // Transformer en array normal ??
    private ArrayList<Mine>         listeMines = new ArrayList<Mine>();
    
    private Hashtable<Actions,Integer> lesCartes = new Hashtable<Actions,Integer>();
    
    private int tankStartX=1, tankStartY=1, tankStartAngle=0;
    
    private TiledMap laMap;
    private TiledMap laMapCopie;
    
    /**
     * Charge la map 'map_[nomMap].tmx', et en extraits ses caractéristiques :
     *  - Nom de la map, auteur, code, map suivante ...
     *  - Cartes dont le joueur va disposer
     *  - Position des différentes cases actions
     *  - Cases à portée de tir de l'ennemi
     *  - L'angle et la position de départ du tank
     * @param nomMap    Nom de la map à chercher, sans préfixe ni extension
     * @throws SlickException 
     */
    public map(String nomMap) throws SlickException {
        
    	nomFichier=nomMap;
    	
        try {
            laMap = new TiledMap(MAP_DIR + nomMap + ".tmx");
            laMapCopie=new TiledMap(MAP_DIR + nomMap + ".tmx");
        } catch (SlickException ex) {
            System.out.println("Impossible de loader la map "+nomFichier+".tmx ! \n"+ex);
        }
        
        
        // On liste les différentes actions dans une matrice
        for (int col=0;col<laMap.getWidth(); col++)
        {
             for (int lig=0;lig<laMap.getHeight(); lig++)
             {
                 int tileID = laMap.getTileId(col, lig, INDEX_ACTIONS);
                 String val = laMap.getTileProperty(tileID, "action", "rien");
                 
                 
                 if       (val.equals("Bloque"))  actionsMap[lig+1][col+1]=Actions.Bloqué;
                 else if  (val.equals("Ennemi"))  actionsMap[lig+1][col+1]=Actions.Ennemi;
                 else if  (val.equals("Mine"))    actionsMap[lig+1][col+1]=Actions.Mine;
                 else if  (val.equals("H"))       actionsMap[lig+1][col+1]=Actions.DirectionH;
                 else if  (val.equals("B"))       actionsMap[lig+1][col+1]=Actions.DirectionB;
                 else if  (val.equals("G"))       actionsMap[lig+1][col+1]=Actions.DirectionG;
                 else if  (val.equals("D"))       actionsMap[lig+1][col+1]=Actions.DirectionD;
                 else if  (val.equals("DB"))      actionsMap[lig+1][col+1]=Actions.DirectionDB;
                 else if  (val.equals("BG"))      actionsMap[lig+1][col+1]=Actions.DirectionBG;
                 else if  (val.equals("GH"))      actionsMap[lig+1][col+1]=Actions.DirectionGH;
                 else if  (val.equals("HD"))      actionsMap[lig+1][col+1]=Actions.DirectionHD;
                 else if  (val.equals("Depart"))  actionsMap[lig+1][col+1]=Actions.Départ;  
                 else if  (val.equals("Arrivee")) actionsMap[lig+1][col+1]=Actions.Fin;
                 else if  (val.equals("Bouclier"))actionsMap[lig+1][col+1]=Actions.Bouclier;
                 else if  (val.equals("Tir"))     actionsMap[lig+1][col+1]=Actions.Tir;
                 else if  (val.equals("Tir4"))    actionsMap[lig+1][col+1]=Actions.Tir4;
                 else if  (val.equals("Plouf"))   actionsMap[lig+1][col+1]=Actions.Plouf;
                 else                             actionsMap[lig+1][col+1]=Actions.Rien;
              
                 // Gestion des cases 'Portée de tir'
                 if (val.equals("Ennemi")) {
                     String angleEnnemi = laMap.getTileProperty(tileID, "angle", "0");
                     int angleE=Integer.valueOf(angleEnnemi);
                     listeEnnemis.add(new TankEnnemi(col+1, lig+1, angleE));
                     
                     // On vire l'image de la map pour mettre l'animation par dessus
                     laMap.setTileId(col, lig, INDEX_ACTIONS, ID_CASE_VIDE);  
                     laMapCopie.setTileId(col, lig, INDEX_ACTIONS, ID_CASE_VIDE);  
                 }
                 
                 // Gestion des mines
                 if (val.equals("Mine")) {
                     listeMines.add(new Mine(col+1, lig+1));
                     
                     // On vire l'image de la map pour mettre l'animation par dessus
                     laMap.setTileId(col, lig, INDEX_ACTIONS, ID_CASE_VIDE);  
                     laMapCopie.setTileId(col, lig, INDEX_ACTIONS, ID_CASE_VIDE); 
                 }
                 
                 if (val.equals("Depart")) {
                     tankStartX=col+1; 
                     tankStartY=lig+1;
                     
                     // On vire l'image de la map pour mettre l'animation par dessus
                     laMap.setTileId(col, lig, INDEX_ACTIONS, ID_CASE_VIDE);  
                     laMapCopie.setTileId(col, lig, INDEX_ACTIONS, ID_CASE_VIDE); 
                 }
                 
             }
         }
           
        actionsOriginalesMap=copier(actionsMap);
        
        // On récupère les propriétés de la carte
        this.nom=laMap.getMapProperty("nom", "/");
        this.auteur=laMap.getMapProperty("auteur", "/");
        this.suivant=laMap.getMapProperty("suivant", "/");
        this.tankStartAngle=Integer.parseInt(laMap.getMapProperty("angle", "0"));

        // On met les cartes d'actions dans une map
        for (Actions i : Actions.values()) {
            lesCartes.put(i, Integer.parseInt(laMap.getMapProperty(i.toString(), "0")));
        }
        
    }
    
    /** 
     * Affiche la carte ( le layer 'paysage' et le layer 'actions' )
     */
    public void dessiner() {
        laMap.render(cases.colToPxl(1), cases.ligToPxl(1),0,0,laMap.getWidth(),laMap.getHeight(), INDEX_MAP, false);
        laMap.render(cases.colToPxl(1), cases.ligToPxl(1),0,0,laMap.getWidth(),laMap.getHeight(), INDEX_ACTIONS, false);
    }
    
    /**
     * Vérifie si la case pointée doit bloquer le joueur
     * @param col   (entre 1 et 15)
     * @param lig
     * @return      Vrai si la case est bloquante
     */
    public boolean case_bloquante(int col, int lig) {
        return actionsMap[lig][col]==Actions.Bloqué;
    }
    

    /**
     * Retourne l'action de la case pointée
     * @param col   (entre 1 et 15)
     * @param lig
     * @return      Action de la case, ou Out si les coordonnées sortent du terrain de jeu
     */
    public Actions action_Case(int col, int lig) {
        if (col>=1 && col <=15 && lig >=1 && lig <=15)
            return this.actionsMap[lig][col];
        else
            return Actions.Out;
    }
    
    /**
     * Ajoute ( ou modifie ) l'action d'une case
     * @param col   (entre 1 et 15)
     * @param lig
     * @param act   L'action à insérer aux coordonnées col/lig
     */ 
    public void ajouter_action(int col, int lig, Actions act) {
        this.actionsMap[lig][col]=act;
    }

    
    /**
     * Détruit un tank ennemi
     * @param col
     * @param lig
     * @see #annuler_portée_de_tir(int col, int lig)
     */
    public void adversaire_detruit(int col, int lig) { 
        //laMap.setTileId(col-1, lig-1, INDEX_ACTIONS, CASE);     
        ajouter_action(col, lig, Actions.Rien);
        
    }
    
    /**
     * Indique si une carte existe ou non
     * @param nom	Le nom de la map
     * @return		Vrai si la map 'nom.tmx' existe
     */
    public static boolean existe(String nom) {
    	File Dossier = new File(MAP_DIR+nom+".tmx");
    	return Dossier.isFile();
    }
    
    /**
     * Retourne le nom de la map
     * @return  Nom de la map
     */
    public String map_nom() {
        return this.nom;
    }
    /**
     * Retourne le code secret de la map
     * @return  Code de la map
     */
    public String map_code() {
        return Crypto.crypt(this.nomFichier.substring(3, 7), 3);
    }
    /**
     * Retourne l'auteur de la map
     * @return  Auteur de la map
     */
    public String map_auteur() {
        return this.auteur;
    }
    /**
     * Retourne la map suivante enregistrée
     * @return  Nom de la map suivante
     */
    public String map_suivante() {
        return this.suivant;
    }    
    
    /**
     * Retourne le nom du fichier de la map
     * @return nom du fichier
     */
    public String map_fichier() {
    	return this.nomFichier;
    }
    /**
     * Retourne la liste des cartes actions que va posséder le joueur
     * @return  Map des cartes actions disponibles
     */
    public Hashtable<Actions,Integer> liste_cartes() {
        return lesCartes;
    }
    
    /**
     * Retourne la liste des ennemis
     * @return Liste des ennemis
     */
    public ArrayList<TankEnnemi> liste_ennemis() {
        return listeEnnemis;
    }
    
    /**
     * Retourne la liste des mines de la map
     * @return Liste des mines
     */
    public ArrayList<Mine> liste_mines() {
        return listeMines;
    }
    /**
     * Réinitialise la map à son état d'origine
     */
    public void reset() {
        this.actionsMap=copier(actionsOriginalesMap);
        
        laMap=laMapCopie;
    }
    
    
    /**
     * Retourne la position de départ du tank
     * @return  Cooord X
     */    
    public int tank_depart_x() {
        return this.tankStartX;
    }
    /** 
     * Retourne la position de départ du tank
     * @return  Coord Y
     */
    public int tank_depart_y() {
        return this.tankStartY;
    }
    /**
     * Retourne la position de départ du tank
     * @return  Angle
     */
    public int tank_depart_angle() {
        return this.tankStartAngle;
    }
    
    
    // ----------------------------------------------------------------//
    
    /**
     * Copie un tableau à 2 dimensions d'actions
     * @param x     le tableau
     * @return      le même tableau
     */
    private static  Actions[][]  copier (Actions[][] x){
      int n = x.length;
      Actions[][] y = new Actions[n][n];
      for (int  i = 0; i < n; i++)
          for (int j=0; j<n; j++)
            y[i][j] = x[i][j];
      return y;
    }
    

}
